package com.meida.module.bus.provider.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.meida.common.base.entity.EntityMap;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.constants.CommonConstants;
import com.meida.common.constants.QueueConstants;
import com.meida.common.constants.SettingConstant;
import com.meida.common.mybatis.base.service.impl.BaseServiceImpl;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.mybatis.query.CriteriaQuery;
import com.meida.common.mybatis.query.CriteriaUpdate;
import com.meida.common.security.OpenHelper;
import com.meida.common.security.OpenUser;
import com.meida.common.utils.ApiAssert;
import com.meida.common.utils.RandomValueUtils;
import com.meida.module.bus.client.entity.AppUserExtra;
import com.meida.module.bus.client.entity.VipType;
import com.meida.module.bus.client.entity.VipUser;
import com.meida.module.bus.provider.mapper.AppUserExtraMapper;
import com.meida.module.bus.provider.service.AppUserExtraService;
import com.meida.module.bus.provider.util.ToolsUtil;
import com.meida.module.file.client.vo.OssSetting;
import com.meida.module.file.provider.enums.StoreTypeEnum;
import com.meida.module.file.provider.service.OssUploadService;
import com.meida.module.pay.client.entity.PayBalance;
import com.meida.module.pay.provider.service.PayBalanceService;
import com.meida.module.user.client.entity.AppAccount;
import com.meida.module.user.client.entity.AppUser;
import com.meida.module.user.provider.handler.BindMobileAfterHandler;
import com.meida.module.user.provider.service.AppAccountService;
import com.meida.module.user.provider.service.AppUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description:用户扩展字段
 * @ClassName AppUserExtraUpdateServiceImpl
 * @date: 2022.06.23 14:41
 * @Author: ldd
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class AppUserExtraServiceImpl extends BaseServiceImpl<AppUserExtraMapper, AppUserExtra> implements AppUserExtraService {

    @Resource
    AppUserService appUserService;

    //# 站点URL
    @Value("${meida.common.site}")
    String site;

    @Autowired(required = false)
    private Map<String, OssUploadService> ossUploadServiceMap;

    @Resource
    PayBalanceService payBalanceService;

    @Resource
    private AppAccountService appAccountService;

    @Autowired(required = false)
    private BindMobileAfterHandler bindMobileAfterHandler;

    @Resource
    private RedisTokenStore redisTokenStore;


    /**
     * 更新前置处理  调用第三方实名认证
     */
    @Override
    public ResultBody beforeEdit(CriteriaUpdate<AppUserExtra> cu, AppUserExtra appUserExtra, EntityMap params) {
        cu.setIdValue(OpenHelper.getUserId());
        return ResultBody.ok();
    }

    @Override
    public EntityMap getAppUserVipInfo(Long inviterId) {
        CriteriaQuery<AppUser> cq = new CriteriaQuery<>(AppUser.class);
        cq.select(AppUser.class, "userId", "userType", "nickName", "avatar", "fullName", "createTime", "openId", "inviterId");
        cq.select(VipType.class, "vipName", "vipCode", "vipTypeId");
        cq.createJoin(VipUser.class).setJoinAlias("vipUser").setMainField("userId").setJoinField("userId");
        cq.createJoin(VipType.class).setMainAlias("vipUser").setMainField("vipTypeId");
        if (inviterId != null && inviterId > 0) {
            cq.eq("user.userId", inviterId);
        } else {
            cq.eq("user.userId", OpenHelper.getUserId());
        }
        EntityMap inviter = appUserService.findOne(cq);

        return inviter;
    }

    @Override
    public EntityMap getMeInfo(Map params) {
        ResultBody resultBody = appUserService.userInit(params);
        EntityMap result = (EntityMap) resultBody.getData();
        EntityMap appUserVipInfo = getAppUserVipInfo(OpenHelper.getUserId());
        PayBalance balance = payBalanceService.getByUserId(OpenHelper.getUserId());
        appUserVipInfo.put("balance", ObjectUtil.isNotNull(balance) ? balance.getAmount().add(balance.getBindAmount()).add(balance.getCommAmount()) : 0);
        result.putAll(appUserVipInfo);
        return result;
    }

    @Override
    public Map sharePoster() {
        //存储方式
        String used = redisUtils.getConfig(SettingConstant.OSS_USED);
        ApiAssert.isNotEmpty("未配置文件上传方式", used);
        StoreTypeEnum storeTypeEnum = StoreTypeEnum.getByName(used);
        ApiAssert.isNotEmpty(used + "文件上传方式不存在", storeTypeEnum);
        //文件上传服务接口
        OssSetting ossSetting = ossUploadServiceMap.get(used).getOssSetting();
        String fileUpload = ossSetting.getFilePath() + "/share/";
        String shareCode = this.getById(OpenHelper.getUserId()).getShareCode();
        String fileName = shareCode + ".jpg";
        if (!FileUtil.exist(fileUpload + fileName)) {
            ToolsUtil.addWatermark(site + "/#/?shareCode=" + shareCode, "邀请码：" + shareCode, fileUpload, fileName);
        }
        Map map = new HashMap();
        map.put("shareUrl", ossSetting.getHttp() + ossSetting.getDomain() + "share/" + fileName);
        return map;
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public AppUser getUserById(Long userId) {
        return appUserService.getById(userId);
    }

    @Override
    public ResultBody removeIdCard(Long id) {
        UpdateWrapper up = new UpdateWrapper();
        up.set("fullName", null);
        up.set("idCard", null);
        up.eq("userId", id);
        boolean update = this.update(up);
        return update ? ResultBody.ok("信息修改成功", update) : ResultBody.failed("信息修改失败");
    }

    @Override
    public ResultBody<AppUser> bingMobile(String mobile, String areaCode, String smsCode, String password, String shareCode, String userType) {
        Long accountId = OpenHelper.getAccountId();
        ApiAssert.isNotEmpty("账户ID异常", accountId);
        redisUtils.validSmsCode(mobile, smsCode);
        //需要绑定的用户
        AppUser appUser = null;
        //获取当前账户
        AppAccount account = appAccountService.getById(accountId);
        //当手机号已注册未绑定时获取手机号账户
        AppAccount mobileAccount = appAccountService.getMobileAccount(mobile);
        if (ObjectUtil.isNotNull(mobileAccount)) {
            appUser = getUserById(mobileAccount.getUserId());
        }
        Long userId = account.getUserId();
        if (FlymeUtils.isNotEmpty(userId)) {
            appUser = getUserById(userId);
        }
        if (ObjectUtils.isEmpty(appUser)) {
            appUser = new AppUser();
            //关联邀请人
            if (FlymeUtils.isNotEmpty(shareCode)) {
                AppUser shareUser = appUserService.getUserByShareCode(shareCode);
                if (FlymeUtils.isNotEmpty(shareUser)) {
                    appUser.setInviterId(shareUser.getUserId());
                }
            }
            appUser.setMobile(mobile);
            //推送扩展事件
            appUser.setNickName(account.getNickName());
            appUser.setAvatar(account.getAvatar());
            appUser.setAreaCode(areaCode);
            if (FlymeUtils.isNotEmpty(userType) && FlymeUtils.isEmpty(appUser.getUserType())) {
                appUser.setUserType(userType);
            }
            initAppUser(appUser);
            appUserService.save(appUser);
            //推送扩展事件
            appUser = (AppUser) amqpTemplate.convertSendAndReceive(QueueConstants.QUEUE_BIND_MOBILE, appUser);
        }
        if (ObjectUtil.isNull(mobileAccount)) {
            appAccountService.registerMobileAccount(appUser.getUserId(), mobile, areaCode, password, true);
        }
        OpenUser openUser = OpenHelper.getUser();
        openUser.setUserId(appUser.getUserId());
        //更新openUser
        OpenHelper.updateOpenUser(redisTokenStore, openUser);
        //关联userId
        UpdateWrapper u = new UpdateWrapper();
        u.set(true, "userId", appUser.getUserId());
        u.eq(true, "accountId", account.getAccountId());
        appAccountService.update(u);
        appUserService.update(new UpdateWrapper<AppUser>().eq("userId", appUser.getUserId()).set("openId", account.getAccount()));
        ResultBody resultBody = initUser(appUser.getUserId());
        if (FlymeUtils.isNotEmpty(bindMobileAfterHandler)) {
            EntityMap data = (EntityMap) resultBody.getData();
            EntityMap entityMap = bindMobileAfterHandler.bindSuccessAfter(appUser.getUserId());
            data.putAll(entityMap);
            resultBody.data(data);
        }
        return resultBody.setMsg("绑定成功");
    }

    /**
     * 初始化用户信息
     *
     * @param appUser
     */
    private void initAppUser(AppUser appUser) {
        Long userId = IdWorker.getId();
        appUser.setUserId(userId);
        appUser.setStatus(CommonConstants.ENABLED);
        //设置userNo
        String userNo = appUserService.createUserNo();
        appUser.setUserNo(userNo);
        //生成邀请码
        appUser.setShareCode(RandomValueUtils.getPromoCode());
        if (FlymeUtils.isEmpty(appUser.getNickName())) {
            appUser.setNickName("游客" + RandomUtil.randomNumbers(5));
        }
        if (FlymeUtils.isEmpty(appUser.getAvatar())) {
            appUser.setAvatar(CommonConstants.DEFAULT_USERHEAD);
        }
    }


    private ResultBody initUser(Long userId) {
        AppAccount user = appAccountService.getById(userId);
        ResultBody resultBody = new ResultBody();
        if (resultBody.isOk() && ObjectUtil.isNotNull(user)) {
            EntityMap map = new EntityMap();
            map.put("accountId", user.getAccountId());
            map.put("accountType", user.getAccountType());
            map.put("userId", userId);
            resultBody.data(map);
        }
        return resultBody;
    }
}
